/*
 * Flashlib - QB9 common Flash library
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package com.qb9.flashlib.fsm
{
	import com.qb9.flashlib.tasks.*;
	import flash.events.*;
	
	/**
	 * Generic State class.
	 *
	 * <p>Instances of <code>State</code> are created by default when calling <code>FSM.registerState()</code>.</p>
	 *
	 * <p>This class can be extended in order to implement custom functionality.</p>
	 */
	public class State extends Task implements IState
	{
		/** Identifier for the special 'initial' state. */
		public static const INITIAL:String = '__initial__';
		/** Identifier for the special 'previous' state. */
		public static const PREVIOUS:String = '__previous__';

		protected var _name:String;
		protected var transitions:Object;
	
		/** Create a State instance. */
		public function State()
		{
			this.transitions = {};
		}

		/** @inheritDoc */
		public function get name():String
		{
			return _name;
		}

		/** @inheritDoc */
		public function set name(n:String):void
		{
			_name = n;
		}
		
		protected function addTransition(t:BaseTransition):Transition
		{
			if (transitions[t.id])
				throw new Error('Transition already defined with id: ' + t.id);
			transitions[t.id] = t;
			return t;
		}

		/** @inheritDoc */
		public function onEvent(type:String, dispatcher:IEventDispatcher = null):Transition
		{
			return addTransition(
				new EventTransition(this, type, dispatcher)
			);
		}

		/** @inheritDoc */
		public function after(milliseconds:uint):Transition
		{
			return addTransition(
				new TimeTransition(this, milliseconds)
			);
		}

		/** @inheritDoc */
		public override function start():void
		{
			super.start();
			for (var type:String in transitions)
				(transitions[type] as BaseTransition).startListening();
		}

		/** @inheritDoc */
		public override function stop():void
		{
			for (var type:String in transitions)
				(transitions[type] as BaseTransition).stopListening();
			super.stop();
		}
		
		/** @inheritDoc */
		public function enter(data:* = null):void
		{
			_elapsed = 0;
			dispatchEvent(new StateEvent(StateEvent.ENTER, data));
		}

		/** @inheritDoc */
		public function exit(data:* = null):void
		{
			dispatchEvent(new StateEvent(StateEvent.EXIT, data));
		}

		internal function requestTransition(next:String, data:* = null):void
		{
			dispatchEvent(new TransitionEvent(next, data));
		}
	}
}
